package com.tjbklx1.redis.chap04;

import java.util.List;
import java.util.Map;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class App42 {
	public static void main(String[] args) throws InterruptedException {
		Jedis conn = new Jedis("localhost");
		conn.select(0);
		new App42().testPurchaseItem(conn);
	}

	private void testPurchaseItem(Jedis conn) {
		System.out.println("\n----- testPurchaseItem -----");
		new App41().testListItem(conn, true); // 引用4.1案例

		System.out.println("We need to set up just enough state so a user can buy an item");
		conn.hset("users:userY", "funds", "125");  // 增加一个买主,资金125,数据类型是 hash
		
		Map<String, String> r = conn.hgetAll("users:userY"); // 遍历买主的信息
		System.out.println("The user has some money:");
		for (Map.Entry<String, String> entry : r.entrySet()) {
			System.out.println("  " + entry.getKey() + ": " + entry.getValue());
		}
		assert r.size() > 0;
		assert r.get("funds") != null;
		System.out.println();

		System.out.println("Let's purchase an item");
		boolean p = purchaseItem(conn, "userY", "itemX", "userX", 10);
		System.out.println("Purchasing an item succeeded? " + p);
		assert p;
		r = conn.hgetAll("users:userY");  //再遍历用户的信息
		System.out.println("Their money is now:");
		for (Map.Entry<String, String> entry : r.entrySet()) {
			System.out.println("  " + entry.getKey() + ": " + entry.getValue());
		}
		assert r.size() > 0;

		String buyer = "userY";
		Set<String> i = conn.smembers("inventory:" + buyer);  //查询买主的库存
		System.out.println("Their inventory is now:");
		for (String member : i) {
			System.out.println("  " + member);
		}
		assert i.size() > 0;
		assert i.contains("itemX");
		assert conn.zscore("market:", "itemX.userX") == null;
	}

	/**
	 * 购买商品
	 * @param conn
	 * @param buyerId
	 * @param itemId
	 * @param sellerId
	 * @param lprice
	 * @return
	 */
	public boolean purchaseItem(Jedis conn, String buyerId, String itemId, String sellerId, double lprice) {

		String buyer = "users:" + buyerId; // 卖主ID
		String seller = "users:" + sellerId; //卖主ID
		String item = itemId + '.' + sellerId; // 卖主的物品
		String inventory = "inventory:" + buyerId; //买主的库存
		long end = System.currentTimeMillis() + 10000;

		while (System.currentTimeMillis() < end) {
			conn.watch("market:", buyer);

			double price = conn.zscore("market:", item); // 获得市场上的物品的价格
			double funds = Double.parseDouble(conn.hget(buyer, "funds")); // 获得买主的资金
			if (price != lprice || price > funds) { // 价格是否变化,买主的资金是否充足
				conn.unwatch();
				return false;
			}

			// transaction方式
			Transaction trans = conn.multi();
			trans.hincrBy(seller, "funds", (int) price); //卖主的资金增加
			trans.hincrBy(buyer, "funds", (int) -price); // 买主的资金减少
			trans.sadd(inventory, itemId); // 买主的库存增加
			trans.zrem("market:", item); //删除市场上的物品
			List<Object> results = trans.exec();
			
			// null response indicates that the transaction was aborted due to the watched key changing.
			if (results == null) {
				continue;
			}
			return true;
		}

		return false;
	}

}
